/*
* Hash the characters
*/
#include "../inc/config.h"
#include "../inc/hash.h"

/* initialize the link table */
Link **init_link(int size){
  Link **link = (Link**)malloc((size + 1) * sizeof(struct node));
  for(int i = 0; i <= size; ++i){
    link[i] = (struct node*)malloc(sizeof(struct node));
    link[i]->next = NULL;
  }
  return link;
}

/* use the elfhash to hash string */
unsigned int elfhash(const char *str) {
  unsigned int h = 0, x = 0;
  while (*str) {
    h = (h << 4) + *str++;
    if ((x = h & 0xF0000000) != 0) {
      h ^= x >> 24;
      h &= ~x;
    }
  }
  return h;
}

/* insert a data to the link table */
void insert(Link **link, const char *data, enum symbol_type type){
    int pos = elfhash(data) & MAP_SIZE;
    struct node *p = link[pos];
    struct node *tmp;
    tmp = (struct node*)malloc(sizeof(struct node));
    tmp->data = (char*)data;
    tmp->type = type;
    tmp->next = p->next;
    p->next = tmp;
}

/* display the every node of the link table */
void show_node(struct node *node){
    if(node->next == NULL){
        printf("\n");
        return;
    }
    while(node->next != NULL){
        node = node->next;
        printf("\"%s\"(%d) --> ", node->data, node->type);
    }
    printf("\n");
}

/* display the link table */
void show_link(Link **link){
    if (link == NULL) return;
    printf("--- show link node ---\n");
    for(int i = 0; i <= MAP_SIZE; ++i){
        printf("%d: ", i);
        show_node(link[i]);
    }
}

/* search the data in the link table */
enum symbol_type search(Link **link, const char *data){
    int pos = elfhash(data) & MAP_SIZE;
    struct node *p = link[pos];
    while(p->next != NULL){
        if(strcmp(p->next->data, data) == 0){
            return p->next->type;
        }
        p = p->next;
    }
    return UNRECOGNIZED;
}

/* free the node in the link table */
void destroy_node(struct node *node){
    if(node->next != NULL){
        while(node->next !=NULL){
            struct node *tmp = node->next;
            node->next = node->next->next;
            free(tmp);
            tmp = NULL;
        }
    }
    free(node);
    node = NULL;
}

/* free the link table */
void destroy_link(Link **link, int size){
    for(int i = 0; i <= size; ++i){
        destroy_node(link[i]);
    }
    free(link);
    link = NULL;
}